#ifndef TIMER_H_JM_20120928
#define TIMER_H_JM_20120928

// ## jm4bbx
#include "../../LogConf.h"
// ## bbx
//#include <upp_mthr.hpp>
// ## boost
#include <boost/date_time/posix_time/posix_time_types.hpp>
// ## c++
#include <ostream>
#include <map>
#include <memory>

namespace jm4bbx {

	struct Timer {
		typedef boost::posix_time::ptime TimeType;		//ulibpp::uUINT64 
		typedef boost::posix_time::time_duration TimeDurationType;

		virtual void start() = 0;
		virtual TimeDurationType meanTime() = 0;
		virtual ~Timer() { }

		TimeType getActualTime() { return  boost::posix_time::microsec_clock::local_time(); }
	};
	typedef std::shared_ptr<Timer> TimerPtr;

	class  PlainTimer : public Timer {
	public:		


		PlainTimer()  { }
		virtual ~PlainTimer() { }

		virtual void start() override ;
		virtual TimeDurationType meanTime() override;

	private:

		TimeType time_;
	};


	class SumTimer : public Timer {
		public:		
			SumTimer() : lapCount_(0), sumTime_(0, 0, 0, 0) { }
			virtual ~SumTimer() { }

			virtual void start() override;
			virtual TimeDurationType meanTime() override;

			size_t getLapCount() const { return lapCount_; }
			TimeDurationType getSumTime() const { return sumTime_; }

		private:
			PlainTimer timer_;
			size_t lapCount_;
			TimeDurationType sumTime_;
	};


	class GlobalTimers {				
	public:	
		typedef std::map<std::string, TimerPtr> GlobalTimersMap;
	


		template<class T>
		struct TimerRegistrator {
			TimerRegistrator(const std::string& timerName) {
				GlobalTimers::registerTimer(timerName, TimerPtr(new T()));
			}
		};


		static void registerTimer(const std::string& timerName, TimerPtr timer) {
			if (timers_ == nullptr) timers_ = new GlobalTimersMap;
			auto it = timers_->find(timerName);
			if (it == timers_->end()) {
				(*timers_)[timerName] = timer;
			}
			else {	
				JM_USE_LOGGER(commonBbx_timer_globalTimers_logger)
				LOG_E("Timer " << timerName << " uz je registrovany.")
				throw std::logic_error(std::string("Timer ") + timerName 
					+ " uz je registrovany.");
			}
		}

		static TimerPtr getTimer(const std::string& timerName);
	private:
		static GlobalTimersMap* timers_;
	};

} // namespace jm4bbx


#endif
